import time
from typing import Callable
from typing import NewType

import keyboard
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.common.action_chains import ActionChains, ActionBuilder
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.keys import Keys

type DoIt = NewType("Do", DoWithElement)


class DoWithElement:

    def __init__(self, css_selector: str, driver: WebDriver):
        self.css_selector = css_selector
        self.actions: list[Callable] = [self.__wait_until_displayed_by_css, self.__deduce_element]
        self.driver = driver
        self.element: WebElement | None = None

    def click(self):
        print(f"click {self.css_selector=}")
        self.actions.append(self.__mouse_click)
        return self

    def select(self):
        return Select(self.element)

    def move_to(self):
        print(f"moving coursor to element {self.css_selector=}")
        self.actions.append(self.__mouse_move)
        return self

    def input_word(self, word: str):
        self.actions.append(lambda: self.__send_keys_from_word_with_delay(word))
        return self

    def do(self):
        print(f"do {self.css_selector=}")
        [x() for x in self.actions]
        self.actions.clear()
        return self

    def __wait_until_displayed_by_css(self, timeout: int | float | None = 10):
        print(f"wait for display {self.css_selector=}")
        wait = WebDriverWait(self.driver, timeout)
        wait.until(lambda d: d.find_element(By.CSS_SELECTOR, self.css_selector).is_displayed())

    def __deduce_element(self):
        print(f"deduce {self.css_selector=}")
        if self.element is None:
            self.element = self.driver.find_element(By.CSS_SELECTOR, self.css_selector)

    def __mouse_click(self):
        print(f"mouse click {self.css_selector=}")
        time.sleep(0.1)
        ActionChains(self.driver).move_to_element(self.element).perform()
        time.sleep(0.1)
        # self.driver.execute_script(f"document.querySelector('{self.css_selector}').click();")
        time.sleep(0.1)
        action = ActionBuilder(self.driver)
        action.pointer_action.click(self.element)
        action.perform()
        time.sleep(0.1)
        ActionChains(self.driver).send_keys(Keys.SHIFT).perform()

    def __mouse_move(self):
        print(f"mouse move {self.css_selector=}")
        (
            ActionChains(self.driver)
            .pause(0.1)
            .move_to_element(self.element)
            .pause(0.1)
            .perform()
        )

    def __send_keys_from_word_with_delay(self, word: str, delay: int | float | None = 0.1):
        print(f"input word {self.css_selector=} {word=}")
        time.sleep(1)
        keyboard.write(word, delay=delay)
        # action_chain = ActionChains(self.driver)
        # [action_chain.send_keys(letter).pause(delay) for letter in word]
        # action_chain.perform()
